Working with Legacy Code

修改軟體

軟體工程師開發時實際上只會針對軟體進行四種改動:

  1. 增加功能:增加軟體過去沒有的行為,通常在程式上增加全新的區塊。
  2. 修改 bug: 對於修改功能依照主觀認定可能視為新增功能或是修改 bug,然而不論是新增功能或是修改 bug 對於軟體來說最大的差異是增加了軟體的行為或變動了軟體的行為。使用者依賴於這些行為,希望我們新增其期許的功能但並不期待既有的行為被移除或改變而需要做出下游變動。
  3. 改善程式架構、改善設計:改變既有的軟體架構使其更好維護,並且不希望更動軟體的行為。在不改變行為前提下進行架構的整理稱為重構,每一個微小的變動都會在測試下驗證其行為不變性,便可以在不改變軟體的行為為前提下使軟體更去可維護性。
  4. 改善程式效能、資源使用(最佳化):類似於重構,不過著重於讓軟體更加有效率的使用硬體資源如時間和記憶體,並且同樣是以不更動軟體的行為為前提。

小結

對一個系統進行修改時,會有三個方面產生改變:結構、行為(功能)、效能。上述四種改動分別主要改變哪些層面:

增加功能 修改 bug 重構 最佳化
結構 改變 改變 改變 -
行為(功能) 改變 改變 - -
效能 - - - 改變

通常增加功能、重構、最佳化理想下會維持既有功能不變,而修改 bug 則會變動既有功能,但這比例佔不變動的功能的比例是很小的。而進行軟體修改,我們九成的精力會花在保持不變的行為而一成的精力會花在修改軟體的行為、效能、結構是正確的。而保持不變的行為並不意味著只要不觸碰那些程式碼即可,而在於在我們希望安全修改軟體需要理解軟體的行為,及這些修改會有哪些連帶的影響。

危險的修改

為了減少修改軟體所伴隨的風險,我們需要考慮三個問題:

以盡量避免改動 code base 的心態進行修改,長久下來是危險的,避免建立新的方法和類別會讓既有的方法和類別變得越來越龐大並難以理解,反之若對需要修改的區塊花一些時間來熟悉,則在後續修改中會更加了解整體的架構,下一次的修改也會更有信心。另一方面,長久不願意接觸既有的程式,久而久之則會對其感到生疏並產生恐懼心理而不易再做改動,隨著時間越久越懼怕修改既有程式,反之應該經常練習接觸則會越來越熟練修改的技巧,並可以輕易辨識哪些程式可以分解哪些不可以。

如何進行修改

對軟體進行變動有兩種主要的方式:

修改遺留程式(Legacy Code)的演算法

  1. 確定程式修改的變動點

要修改的地點和程式碼的架構會有緊密連繫可能有著高相依性。若對程式的理解程度不足,導致難以判斷正確的修改點的話可以參考對程式碼理解不足的解方程式碼毫無邏輯可言的解方

  1. 找出測試點

對於遺留的程式碼難以找到測試點的話可以參考修改時應測試哪些方法在同一地方進行多處修改,是否應對所有相關的類別都解依賴

  1. 解依賴

依賴性是測試的最大阻礙,包含難以在測試控制工具中實例化的目標物件,也難以在測試控制工具中執行的方法。通常在遺留程式中需要先解依賴後才能夠將測試放置其中。在無法將類別放置測試控制工具中無法在測試控制工具中執行方法提供了一般解依賴問題的方法,進一步可以參考解依賴技術。通常解依賴本身的程式碼也需要受到測試的保護,在降低修改的風險提供了實作的方法讓所做的第一個變動可以收到測試保護而變得更安全。

  1. 編寫測試

測試新編寫的程式碼和測試遺留程式碼有些許不同,可以參考修改時應該怎麼寫測試

  1. 修改及重構

在測試前提下進行改動理想上可以透過測試驅動開發來為遺留程式碼增加新功能,在遺留程式碼添加功能中提及了 TDD和其他添加功能的技術。而隨著對程式碼的了解越深後往往可以多做一些重構,在處理大類別需要修改大量相同的程式碼要修改一個巨型方法但無法為其編寫測試中有提及可以讓遺留程式碼程式結構更好的技術